home *** CD-ROM | disk | FTP | other *** search
Oberon Text | 1995-04-11 | 10.8 KB | 323 lines | [TEXT/.Ob4] |
- Syntax10.Scn.Fnt
- MODULE Kepler6;
- (* Semesterarbeit Wintersemester 91/92 von Samuel Urech
- Erweiterung des Graphikeditors Kepler um Splines
- Programmiersprache: Oberon-2 auf Ceres-1
- Autor: Samuel Urech, Tannenrauchstrasse 35/107, 8038 Z
- Tel. 01 481 92 92 Stud.Nr. 87-906-434
- Datum: 4.11.91 Stand: 6.2.92
- J. Templ, 18.06.92, NewClosedBezier intriduced, NewOpenCRSpline renamed to NewCRSpline
- J. Templ, 01.07.93 expressions simplified
- IMPORT KeplerPorts, KeplerGraphs, KeplerFrames, Display, Math;
- CONST Eps = 1.0E-6;
- TYPE
- CRSpline* = POINTER TO CRSplineDesc;
- CRSplineDesc* = RECORD
- ( KeplerGraphs.ConsDesc )
- END;
- Bezier* = POINTER TO BezierDesc;
- BezierDesc* = RECORD
- ( KeplerGraphs.ConsDesc )
- END;
- PROCEDURE Min( a, b : INTEGER ) : INTEGER;
- BEGIN (* Min *)
- IF a < b THEN RETURN a
- ELSE RETURN b
- END;
- END Min;
- PROCEDURE Max( a, b : INTEGER ) : INTEGER;
- BEGIN (* Max *)
- IF a < b THEN RETURN b
- ELSE RETURN a
- END;
- END Max;
- PROCEDURE GetBoundingBox( a3, a2, a1, a0, b3, b2, b1, b0 : REAL;
- x1, y1, x2, y2 : INTEGER;
- VAR x, y, w, h : INTEGER );
- (* Berechnet ein Rechteck, in dem sich das zu zeichnende Kurvenst
- ck vollst
- ndig befindet.
- a3, a2, a1, a0, b3, b2, b1, b0 sind die Koeffizienten der Kurve,
- x1, y1, x2, y2 sind die Randpunkte. *)
- VAR t, rt, temp : REAL;
- x3, x4, y3, y4 : INTEGER;
- BEGIN (* GetBoundingBox *)
- IF ABS( a3 ) < Eps THEN
- IF ABS( a2 ) < Eps THEN
- x := Min( x1, x2 );
- w := ABS( x2 - x1 );
- ELSE
- t := 0.5 * a1 / a2;
- temp := t * ( a2 + t * a3 );
- x3 := SHORT( ENTIER( a0 + t * ( a1 + temp ) ) );
- x := Min( x1, Min( x2, x3 - 1 ) );
- w := Max( x1, Max( x2, x3 + 1 ) ) - x;
- END; (* IF *)
- ELSE
- rt := a2 * a2 - 3.0 * a1 * a3;
- IF rt < 0 THEN
- x := Min( x1, x2 );
- w := ABS( x2 - x1 );
- ELSE
- rt := Math.sqrt( rt );
- t := ( -a2 - rt ) / 3 / a3;
- IF ( t > 0 ) & ( t < 1 ) THEN
- temp := t * ( a2 + t * a3 );
- x3 := SHORT( ENTIER( a0 + t * ( a1 + temp ) ) );
- ELSE
- x3 := x1;
- END;
- t := ( -a2 + rt ) / 3 / a3;
- IF ( t > 0 ) & ( t < 1 ) THEN
- temp := t * ( a2 + t * a3 );
- x4 := SHORT( ENTIER( a0 + t * ( a1 + temp ) ) );
- ELSE
- x4 := x1;
- END; (* IF *)
- x := Min( x1, Min( x2, Min( x3, x4 ) - 1 ) );
- w := Max( x1, Max( x2, Max( x3, x4 ) + 1 ) ) - x;
- END; (* IF *)
- END; (* IF *)
- IF ABS( b3 ) < Eps THEN
- IF ABS( b2 ) < Eps THEN
- y := Min( y1, y2 );
- h := ABS( y2 - y1 );
- ELSE
- t := 0.5 * b1 / b2;
- temp := t * ( b2 + t * b3 );
- y3 := SHORT( ENTIER( b0 + t * ( b1 + temp ) ) );
- y := Min( y1, Min( y2, x3 - 1 ) );
- h := Max( y1, Max( y2, y3 + 1 ) ) - y;
- END; (* IF *)
- ELSE
- rt := b2 * b2 - 3.0 * b1 * b3;
- IF rt < 0 THEN
- y := Min( y1, y2 );
- h := ABS( y2 - y1 );
- ELSE
- rt := Math.sqrt( rt );
- t := ( -b2 - rt ) / 3 / b3;
- IF ( t > 0 ) & ( t < 1 ) THEN
- temp := t * ( b2 + t * b3 );
- y3 := SHORT( ENTIER( b0 + t * ( b1 + temp ) ) );
- ELSE
- y3 := y1;
- END;
- t := ( -b2 + rt ) / 3 / b3;
- IF ( t > 0 ) & ( t < 1 ) THEN
- temp := t * ( b2 + t * b3 );
- y4 := SHORT( ENTIER( b0 + t * ( b1 + temp ) ) );
- ELSE
- y4 := y1;
- END; (* IF *)
- y := Min( y1, Min( y2, Min( y3, y4 ) - 1 ) );
- h := Max( y1, Max( y2, Max( y3, y4 ) + 1 ) ) - y;
- END; (* IF *)
- END; (* IF *)
- DEC( x, 2 ); DEC( y, 2 ); INC( w, 4 ); INC( h, 4 );
- END GetBoundingBox;
- PROCEDURE Intersect( f : KeplerPorts.Port; x, y, w, h : INTEGER ) : BOOLEAN;
- (* Pr
- ft, ob sich der Frame f mit dem Rechteck ( x, y, w, h )
- berschneidet. *)
- VAR t : INTEGER;
- BEGIN (* Intersect *)
- x := f.CX( x ); y := f.CY( y ); w := w DIV f.scale; h := h DIV f.scale;
- t := x + w;
- IF f.X > x THEN x := f.X END;
- IF f.X + f.W < t THEN
- w := f.X + f.W - x;
- ELSE
- w := t - x;
- END;
- IF w <= 0 THEN RETURN FALSE END;
- t := y + h;
- IF f.Y > y THEN y := f.Y END;
- IF f.Y + f.H < t THEN
- h := f.Y + f.H - y;
- ELSE
- h := t - y;
- END;
- RETURN h > 0
- END Intersect;
- PROCEDURE DrawCurve( f : KeplerPorts.Port; a3, a2, a1, a0, b3, b2, b1, b0 : REAL );
- (* Zeichnet die Kurve mit den Koeffizienten a3, a2, a1, a0, b3, b2, b1, b0 in den Frame f. *)
- PROCEDURE DrawRec( lo, hi : REAL );
- (* Zeichnet rekursiv den Spline im Bereich lo, hi. *)
- VAR xlo, xhi, ylo, yhi : INTEGER;
- med : REAL;
- BEGIN (* DrawRec *)
- xlo := SHORT( ENTIER( a0 + lo * ( a1 + lo * ( a2 + lo * a3 ) ) ) );
- xhi := SHORT( ENTIER( a0 + hi * ( a1 + hi * ( a2 + hi * a3 ) ) ) );
- ylo := SHORT( ENTIER( b0 + lo * ( b1 + lo * ( b2 + lo * b3 ) ) ) );
- yhi := SHORT( ENTIER( b0 + hi * ( b1 + hi * ( b2 + hi * b3 ) ) ) );
- IF ABS( xhi - xlo ) + ABS( yhi - ylo ) <= 2 * f.scale THEN
- f.DrawLine( xlo, ylo, xhi, yhi, Display.white, Display.replace );
- ELSE
- med := ( lo + hi ) / 2;
- DrawRec( lo, med );
- DrawRec( med, hi );
- END; (* IF *)
- END DrawRec;
- BEGIN (* DrawCurve *)
- DrawRec( 0, 1 );
- END DrawCurve;
- (* ------------------------------ Catmull-Rom Spline ----------------------------------- *)
- PROCEDURE ( s : CRSpline ) Draw*( f : KeplerPorts.Port );
- (* druckt ein Catmull-Rom Spline auf den Bildschirm *)
- VAR a3, a2, a1, a0, b3, b2, b1, b0 : REAL;
- x, y, w, h, t : INTEGER;
- BEGIN (* Draw *)
- t := s.p[ 3 ].x - 3 * s.p[ 2 ].x; a3 := ( t + 3 * s.p[ 1 ].x - s.p[ 0 ].x ) / 2;
- t := -s.p[ 3 ].x + 4 * s.p[ 2 ].x; a2 := ( t - 5 * s.p[ 1 ].x + 2 * s.p[ 0 ].x ) / 2;
- a1 := ( s.p[ 2 ].x - s.p[ 0 ].x ) / 2;
- a0 := s.p[ 1 ].x;
- t := s.p[ 3 ].y - 3 * s.p[ 2 ].y; b3 := ( t + 3 * s.p[ 1 ].y - s.p[ 0 ].y ) / 2;
- t := -s.p[ 3 ].y + 4 * s.p[ 2 ].y; b2 := ( t - 5 * s.p[ 1 ].y + 2 * s.p[ 0 ].y ) / 2;
- b1 := ( s.p[ 2 ].y - s.p[ 0 ].y ) / 2;
- b0 := s.p[ 1 ].y;
- GetBoundingBox( a3, a2, a1, a0, b3, b2, b1, b0, s.p[ 1 ].x, s.p[ 1 ].y, s.p[ 2 ].x, s.p[ 2 ].y, x, y, w, h );
- IF f IS KeplerPorts.BalloonPort THEN
- f.DrawRect( x, y, w, h, 0, 0 );
- ELSIF Intersect( f, x, y, w, h ) THEN
- DrawCurve( f, a3, a2, a1, a0, b3, b2, b1, b0 );
- END;
- END Draw;
- PROCEDURE NewCRSpline*;
- (* Liest alle Fokuspunkte ein und legt ein Catmull-Rom Spline durch sie hindurch. *)
- VAR s, s1 : CRSpline;
- BEGIN (* NewOpenCRSpline *)
- IF KeplerFrames.nofpts >= 4 THEN
- NEW( s );
- s.nofpts := 4;
- KeplerFrames.ConsumePoint( s.p[ 0 ] );
- KeplerFrames.ConsumePoint( s.p[ 1 ] );
- KeplerFrames.ConsumePoint( s.p[ 2 ] );
- KeplerFrames.ConsumePoint( s.p[ 3 ] );
- KeplerFrames.Focus.Append( s );
- WHILE KeplerFrames.nofpts > 0 DO
- NEW( s1 );
- s1.nofpts := 4;
- s1.p[ 0 ] := s.p[ 1 ]; INC( s1.p[ 0 ].refcnt );
- s1.p[ 1 ] := s.p[ 2 ]; INC( s1.p[ 1 ].refcnt );
- s1.p[ 2 ] := s.p[ 3 ]; INC( s1.p[ 2 ].refcnt );
- KeplerFrames.ConsumePoint( s1.p[ 3 ] );
- s := s1;
- KeplerFrames.Focus.Append( s );
- END; (* WHILE *)
- END; (* IF *)
- END NewCRSpline;
- PROCEDURE NewClosedCRSpline*;
- (* Liest alle Fokuspunkte ein und legt ein geschlossenes Catmull-Rom Spline durch sie hindurch. *)
- VAR s, s1 : CRSpline;
- point : ARRAY 3 OF KeplerGraphs.Star;
- i : INTEGER;
- BEGIN (* NewClosedCRSpline *)
- IF KeplerFrames.nofpts >= 4 THEN
- NEW( s );
- s.nofpts := 4;
- KeplerFrames.ConsumePoint( s.p[ 0 ] ); point[ 0 ] := s.p[ 0 ];
- KeplerFrames.ConsumePoint( s.p[ 1 ] ); point[ 1 ] := s.p[ 1 ];
- KeplerFrames.ConsumePoint( s.p[ 2 ] ); point[ 2 ] := s.p[ 2 ];
- KeplerFrames.ConsumePoint( s.p[ 3 ] );
- KeplerFrames.Focus.Append( s );
- WHILE KeplerFrames.nofpts > 0 DO
- NEW( s1 );
- s1.nofpts := 4;
- s1.p[ 0 ] := s.p[ 1 ]; INC( s1.p[ 0 ].refcnt );
- s1.p[ 1 ] := s.p[ 2 ]; INC( s1.p[ 1 ].refcnt );
- s1.p[ 2 ] := s.p[ 3 ]; INC( s1.p[ 2 ].refcnt );
- KeplerFrames.ConsumePoint( s1.p[ 3 ] );
- s := s1;
- KeplerFrames.Focus.Append( s );
- END; (* WHILE *)
- FOR i := 0 TO 2 DO
- NEW( s1 );
- s1.nofpts := 4;
- s1.p[ 0 ] := s.p[ 1 ]; INC( s1.p[ 0 ].refcnt );
- s1.p[ 1 ] := s.p[ 2 ]; INC( s1.p[ 1 ].refcnt );
- s1.p[ 2 ] := s.p[ 3 ]; INC( s1.p[ 2 ].refcnt );
- s1.p[ 3 ] := point[ i ]; INC( s1.p[ 3 ].refcnt );
- s := s1;
- KeplerFrames.Focus.Append( s );
- END; (* FOR *)
- END; (* IF *)
- END NewClosedCRSpline;
- (* ----------------------------------- Bezier-Kurve ------------------------------- *)
- PROCEDURE ( s : Bezier ) Draw*( f : KeplerPorts.Port );
- (* Druckt eine Bezier-Kurve auf den Bildschirm *)
- VAR a3, a2, a1, a0, b3, b2, b1, b0 : INTEGER;
- x, y, w, h, t : INTEGER;
- BEGIN (* Draw *)
- t := 3 * s.p[ 3 ].x - 5 * s.p[ 2 ].x; a3 := t + 3 * s.p[ 1 ].x - s.p[ 0 ].x;
- t := -3 * s.p[ 3 ].x + 6 * s.p[ 2 ].x; a2 := t - 6 * s.p[ 1 ].x + 3 * s.p[ 0 ].x;
- a1 := ( s.p[ 1 ].x - s.p[ 0 ].x ) * 3;
- a0 := s.p[ 0 ].x;
- t := 3 * s.p[ 3 ].y - 5 * s.p[ 2 ].y; b3 := t + 3 * s.p[ 1 ].y - s.p[ 0 ].y;
- t := -3 * s.p[ 3 ].y + 6 * s.p[ 2 ].y; b2 := t - 6 * s.p[ 1 ].y + 3 * s.p[ 0 ].y;
- b1 := ( s.p[ 1 ].y - s.p[ 0 ].y ) * 3;
- b0 := s.p[ 0 ].y;
- GetBoundingBox( a3, a2, a1, a0, b3, b2, b1, b0, s.p[ 0 ].x, s.p[ 0 ].y, a3 + a2 + a1 + a0, b3 + b2 + b1 + b0, x, y, w, h );
- IF f IS KeplerPorts.BalloonPort THEN
- f.DrawRect( x, y, w, h, 0, 0 );
- ELSIF Intersect( f, x, y, w, h ) THEN
- DrawCurve( f, a3, a2, a1, a0, b3, b2, b1, b0 );
- END;
- END Draw;
- PROCEDURE NewBezier*;
- (* Liest eine gerade Anzahl Fokuspunkte ein und legt eine Bezier-Kurve durch sie hindurch. *)
- VAR s, s1 : Bezier;
- BEGIN
- IF KeplerFrames.nofpts >= 4 THEN
- NEW( s );
- s.nofpts := 4;
- KeplerFrames.ConsumePoint( s.p[ 0 ] );
- KeplerFrames.ConsumePoint( s.p[ 1 ] );
- KeplerFrames.ConsumePoint( s.p[ 2 ] );
- KeplerFrames.ConsumePoint( s.p[ 3 ] );
- KeplerFrames.Focus.Append( s );
- WHILE KeplerFrames.nofpts > 1 DO
- NEW( s1 );
- s1.nofpts := 4;
- s1.p[ 0 ] := s.p[ 2 ]; INC( s1.p[ 0 ].refcnt );
- s1.p[ 1 ] := s.p[ 3 ]; INC( s1.p[ 1 ].refcnt );
- KeplerFrames.ConsumePoint( s1.p[ 2 ] );
- KeplerFrames.ConsumePoint( s1.p[ 3 ] );
- s := s1;
- KeplerFrames.Focus.Append( s );
- END; (* WHILE *)
- END; (* IF *)
- END NewBezier;
- PROCEDURE NewClosedBezier*;
- (* Liest eine gerade Anzahl Fokuspunkte ein und legt eine Bezier-Kurve durch sie hindurch. *)
- VAR s, s1, s0 : Bezier;
- BEGIN
- IF KeplerFrames.nofpts >= 4 THEN
- NEW( s ); s0 := s; s1 := s;
- s.nofpts := 4;
- KeplerFrames.ConsumePoint( s.p[ 0 ] );
- KeplerFrames.ConsumePoint( s.p[ 1 ] );
- KeplerFrames.ConsumePoint( s.p[ 2 ] );
- KeplerFrames.ConsumePoint( s.p[ 3 ] );
- KeplerFrames.Focus.Append( s );
- WHILE KeplerFrames.nofpts > 1 DO
- NEW( s1 );
- s1.nofpts := 4;
- s1.p[ 0 ] := s.p[ 2 ]; INC( s1.p[ 0 ].refcnt );
- s1.p[ 1 ] := s.p[ 3 ]; INC( s1.p[ 1 ].refcnt );
- KeplerFrames.ConsumePoint( s1.p[ 2 ] );
- KeplerFrames.ConsumePoint( s1.p[ 3 ] );
- s := s1;
- KeplerFrames.Focus.Append( s )
- END ;
- NEW(s);
- s.nofpts := 4;
- s.p[ 0 ] := s1.p[ 2 ]; INC(s.p[ 0 ].refcnt);
- s.p[ 1 ] := s1.p[ 3 ]; INC(s.p[ 1 ].refcnt);
- s.p[ 2 ] := s0.p[ 0 ]; INC(s.p[ 2 ].refcnt);
- s.p[ 3 ] := s0.p[ 1 ]; INC(s.p[ 3 ].refcnt);
- KeplerFrames.Focus.Append( s )
- END
- END NewClosedBezier;
- END Kepler6.
-